//    entity language compiler Copyright (C) 2011 Vincent Belliard

//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation version 3 of the License.

//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.

//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <typeinfo>
#include "types.h"
#include "entity.h"
#include "method.h"
#include "type.h"
#include "expression.h"
#include "global.h"
#include "object_class.h"
#include "scope.h"

// }{--------------------------------------------------------------

int T_expression::search_field(T_entity_program *program, const T_string name, T_expression_identifier_access *identifier_access)
{
const T_object_class_field *field = type->search_field(program, TRUE, name) ;
if (field != NULL)
	{
	identifier_access->field = field ;
	identifier_access->type = field->type ;
	return TRUE ;
	}
return FALSE ;
}

// }{--------------------------------------------------------------

void T_expression_block::dump(FILE *file) const
{
fprintf(file, "\n{\n") ;
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	expression->dump(file) ;
	if (expression->is_block()) fprintf(file, "\n") ;
	else fprintf(file, " ;\n") ;
	expression = expression->next ;
	}
fprintf(file, "}") ;
}

void T_expression_block::parse(T_entity_compiler *compiler)
{
//compiler->add_error(compiler->location, "block start %p", this) ;
for(;;)
	{
	if (compiler->current_item == entity_compiler_item_eof)
		{
		compiler->add_error(location, "block unterminated.") ;
		return ;
		}
	if (compiler->current_item == entity_compiler_item_right_brace)
		{
//compiler->add_error(compiler->location, "block end %p", this) ;
		compiler->next_item() ;
		return ;
		}
	T_expression *loc = compiler->parse_expression() ;
	if (loc == NULL)
		{
		compiler->add_error(compiler->location, "expression expected.") ;
		compiler->skip_semicolon() ;
		}
	else
		{
		expressions.insert(loc) ;
		if (!loc->instruction && !loc->is_block())
			{
			if (compiler->current_item == entity_compiler_item_semicolon)
				{
				compiler->next_item() ;
				loc->instruction = TRUE ;
				}
			else if (compiler->current_item != entity_compiler_item_right_brace)
				{
				compiler->add_error(compiler->location, "semicolon expected.") ;
				}
			}
		}
	}
}

int T_expression_block::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
T_block_scope scope_loc(scope) ;
int result = TRUE ;
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	if (dead)
		{
		compiler->add_error(expression->location, "Unreachable code.") ;
		result = FALSE ;
		}
	if (!expression->verify_semantic(compiler, program, &scope_loc, method_type))
		{
		result = FALSE ;
		}
	else
		{
		type = expression->type ;
		if (expression->dead) dead = TRUE ;
		if (expression->test)
			{
			test = TRUE ;
			if (expression->next != NULL) compiler->add_error(expression->location, "test not expected here.") ;
			}
		if (type == NULL)
			{
			compiler->add_error(expression->location, "type NULL for %s", expression->get_name()) ;
			}
		else if (!type->is_void() && (expression->next != NULL))
			{
			compiler->add_error(expression->location, "block : No value expected here.") ;
			result = FALSE ;
			}
		}
	expression = expression->next ;
	}
return result ;
}

void T_expression_block::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
fprintf(file, "//block : generate_test\n") ;
fprintf(file, "{\n") ;
T_expression *expression = expressions.first ;
while (expression->next != NULL)
	{
	expression->generate_instruction(program, file) ;
	expression = expression->next ;
	}
expression->generate_test(program, file, jump_if_true, true_label, false_label) ;
fprintf(file, "}\n") ;
}

void T_expression_block::generate_instruction(T_entity_program *program, FILE *file)
{
fprintf(file, "{\n") ;
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	expression->generate_instruction(program, file) ;
	expression = expression->next ;
	}
fprintf(file, "}\n") ;
}

// }{--------------------------------------------------------------

void T_expression_integer::dump(FILE *file) const
{
fprintf(file, "%llu", value) ;
}

int T_expression_integer::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (value <= 0x7F) type = new T_type_identifier(location, program->integer_8_class) ;
else if (value < 0x7FFF) type = new T_type_identifier(location, program->integer_16_class) ;
else if (value < 0x7FFFFFFF) type = new T_type_identifier(location, program->integer_32_class) ;
else type = new T_type_identifier(location, program->integer_64_class) ;
return TRUE ;
}

void T_expression_integer::generate(T_entity_program *program, FILE *file, int generate_type)
{
fprintf(file, "%llu", value) ;
}

// }{--------------------------------------------------------------

void T_expression_string::dump(FILE *file) const
{
fprintf(file, "\"%s\"", value.string()) ;
}

int T_expression_string::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
index = program->get_next_index() ;
type = new T_type_identifier(location, program->string_class) ;
return TRUE ;
}

void T_expression_string::prepare(T_entity_program *program, FILE *file)
{
fprintf(file, "T_string string_%d(\"%s\") ;\n", index, value.string()) ;
}

void T_expression_string::generate(T_entity_program *program, FILE *file, int generate_type)
{
fprintf(file, "string_%d", index) ;
}

// }{--------------------------------------------------------------

void T_expression_identifier::dump(FILE *file) const
{
fprintf(file, "%s", value.string()) ;
}

int T_expression_identifier::search_field(T_entity_program *program, const T_string name, T_expression_identifier_access *identifier_access)
{
if (T_expression::search_field(program, name, identifier_access)) return TRUE ;
if (object_class != NULL)
	{
	T_object_class_value *value = object_class->search_value(name) ;
	if (value != NULL)
		{
		identifier_access->value = value ;
		identifier_access->type = new T_type_identifier(location, object_class) ;
		return TRUE ;
		}
	}
return FALSE ;
}

int T_expression_identifier::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
T_scope *scope_loc = scope ;
while (scope_loc != NULL)
	{
	if (scope_loc->search_identifier(this, value)) return TRUE ;
	scope_loc = scope_loc->previous_scope ;
	}
object_class = program->search_class(value) ;
if (object_class != NULL)
	{
	type = new T_type_identifier(location, program->type_class) ;
	if (object_class->constructors.first != NULL)
		{
		constructor = object_class->search_constructor(program, NULL) ;
/*
		if (constructor == NULL)
			{
			compiler->add_error(location, "constructor not found.") ;
			return FALSE ;
			}
*/
		}
	return TRUE ;
	}
global = program->search_global(value) ;
if (global != NULL)
	{
//fprintf(stderr,"%p : use of %p : type=%p\n", this, global, global->type) ;
	type = global->type ;
	return TRUE ;
	}
compiler->add_error(location, "identifier <%s> not found.", value.string()) ;
return FALSE ;
}

int T_expression_identifier::verify_call_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type, T_expression_call_access *call)
{
//fprintf(stderr, "search call %s\n", value.string()) ;
object_class = program->search_class(value) ;
if (object_class != NULL)
	{
	type = new T_type_identifier(location, object_class) ;
	constructor = object_class->search_constructor(program, call) ;
	if (constructor == NULL)
		{
		compiler->add_error(location, "constructor not found.") ;
		return FALSE ;
		}
	call->constructor = constructor ;
	return TRUE ;
	}
T_scope *scope_loc = scope ;
for(;;)
	{
	if (scope_loc == NULL)
		{
		compiler->add_error(location, "method <%s> not found.", value.string()) ;
		return FALSE ;
		}
	if (scope_loc->is_method())
		{
		method = ((T_object_class_method_scope *)scope_loc)->method->object_class->search_call(program, value, call) ;
//fprintf(stderr, "type=%d => method=%p\n", expression->type->get_class(), method) ;
		if (method == NULL)
			{
			compiler->add_error(call->location, "bad call to %s.", value.string()) ;
			return FALSE ;
			}
		type = method->type->returned_type ;
		test = method->type->test ;
		return TRUE ;
		}
	if (scope_loc->is_constructor())
		{
		method = ((T_object_class_constructor_scope *)scope_loc)->constructor->object_class->search_call(program, value, call) ;
//fprintf(stderr, "type=%d => method=%p\n", expression->type->get_class(), method) ;
		if (method == NULL)
			{
			compiler->add_error(call->location, "bad call to %s.", value.string()) ;
			return FALSE ;
			}
		type = method->type->returned_type ;
		test = method->type->test ;
		return TRUE ;
		}
	scope_loc = scope_loc->previous_scope ;
	}
}

void T_expression_identifier::generate(T_entity_program *program, FILE *file, int generate_type)
{
if (global != NULL)
	{
	fprintf(file, "(&%s.data)", value.string()) ;
	}
else if (local != NULL)
	{
	switch (generate_type)
		{
		case type_generate_value:
			if (local->is_reference()) fprintf(file, "(*local_%s)", value.string()) ;
			else fprintf(file, "local_%s.data", value.string()) ;
			break ;
		case type_generate_class_reference:
			if (local->is_reference()) fprintf(file, "local_%s", value.string()) ;
			else fprintf(file, "(&local_%s.data)", value.string()) ;
			break ;
		}
	}
else if (argument != NULL)
	{
	switch (generate_type)
		{
		case type_generate_value:
			if (argument->is_reference) fprintf(file, "(*arg_%s)", value.string()) ;
			else fprintf(file, "arg_%s", value.string()) ;
			break ;
		case type_generate_class_reference:
			if (argument->is_reference) fprintf(file, "arg_%s", value.string()) ;
			else fprintf(file, "(&arg_%s)", value.string()) ;
			break ;
		}
	}
else if (field != NULL)
	{
	switch (generate_type)
		{
		case type_generate_value:
			if (field->type->is_reference()) fprintf(file, "(*arg_self->_%s)", field->name.string()) ;
			else fprintf(file, "arg_self->_%s", field->name.string()) ;
			break ;
		case type_generate_class_reference:
			if (field->type->is_reference()) fprintf(file, "arg_self->_%s", field->name.string()) ;
			else fprintf(file, "(&arg_self->_%s)", field->name.string()) ;
			break ;
		}
	}
}

void T_expression_identifier::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
if (jump_if_true)
	{
	fprintf(file, "if (test(") ;
	generate(program, file, type_generate_value) ;
	fprintf(file, ")) ") ;
	if (true_label == 0) fprintf(file, "break ;\n") ;
	else fprintf(file, "goto label_%d ;\n", true_label) ;
	}
else
	{
	fprintf(file, "if (!test(") ;
	generate(program, file, type_generate_value) ;
	fprintf(file, ")) ") ;
	if (false_label == 0) fprintf(file, "break ;\n") ;
	else fprintf(file, "goto label_%d ;\n", false_label) ;
	}
}

void T_expression_identifier::prepare_call(T_entity_program *program, FILE *file, const T_expression_call_access *call)
{
T_expression *loc = call->expressions.first ;
while (loc != NULL)
	{
	loc->prepare(program, file) ;
	loc = loc->next ;
	}
}

void T_expression_identifier::generate_call(T_entity_program *program, FILE *file, const T_expression_call_access *call)
{
if (method->overloaded)
	{
	fprintf(file, "((HEADER_%s", method->object_class->name.string()) ;
	fprintf(file, "*)arg_self)[-1].introspect->virtual_%s__%s(", method->object_class->name.string(), method->name.string()) ;
	}
else
	{
	fprintf(file, " _%s__%s(", method->object_class->name.string(), method->name.string()) ;
	}
int first = TRUE ;
T_prototype_argument *argument = method->type->prototype.arguments.first ;
T_expression *loc = call->expressions.first ;
while (argument != NULL)
	{
	if (first) first = FALSE ;
	else fprintf(file, ", ") ;
	if (strcmp(argument->name.string(), "self") == 0)
		{
		fprintf(file, "(") ;
		argument->type->generate_type_name(file, type_generate_class_reference) ;
		fprintf(file, ")arg_self") ;
		}
	else if (loc != NULL)
		{
		loc->generate(program, file, argument->is_reference ? type_generate_class_reference : type_generate_value) ;
		loc = loc->next ;
		}
	else
		{
		fprintf(file, "empty_vector") ;
		}
	argument = argument->next ;
	}
fprintf(file, ")") ;
}

void T_expression_identifier::generate_constructor(T_entity_program *program, FILE *file, const T_string name)
{
if (constructor != NULL) fprintf(file, "constructor_%p(&local_%s.data) ;\n", constructor, name.string()) ;
}

void T_expression_identifier::generate_constructor(T_entity_program *program, FILE *file, const T_string name, const T_expression_call_access *call)
{
fprintf(file, "constructor_%p(&local_%s.data", constructor, name.string()) ;
T_prototype_argument *argument = constructor->prototype.arguments.first ;
if (argument != NULL) argument = argument->next ;
T_expression *loc = call->expressions.first ;
while (argument != NULL)
	{
	if (strcmp(argument->name.string(), "self") == 0)
		{
//		fprintf(file, "(") ;
//		argument->type->generate_type_name(file, type_generate_class_reference) ;
//		fprintf(file, ")local_%s", name.string()) ;
		}
	else if (loc != NULL)
		{
		fprintf(file, ", ") ;
		loc->generate(program, file, argument->is_reference ? type_generate_class_reference : type_generate_value) ;
		loc = loc->next ;
		}
	else
		{
		fprintf(file, ", ") ;
		fprintf(file, "empty_vector") ;
		}
	argument = argument->next ;
	}
fprintf(file, ") ;\n") ;
}

// }{--------------------------------------------------------------

void T_expression_boolean::dump(FILE *file) const
{
fprintf(file, "%s", value ? "true" : "false") ;
}

int T_expression_boolean::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
type = new T_type_identifier(location, program->boolean_class) ;
return TRUE ;
}

void T_expression_boolean::generate(T_entity_program *program, FILE *file, int generate_type)
{
fprintf(file, "%s", value ? "TRUE" : "FALSE") ;
}

void T_expression_boolean::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
fprintf(file, "//boolean : generate_test\n") ;
int label ;
if (jump_if_true)
	{
	if (!value) return ;
	label = true_label ;
	}
else
	{
	if (value) return ;
	label = false_label ;
	}
if (label == 0) fprintf(file, "break ;\n") ;
else fprintf(file, "goto label_%d ;\n", label) ;
}

// }{--------------------------------------------------------------

void T_expression_null::dump(FILE *file) const
{
fprintf(file, "null") ;
}

int T_expression_null::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
type = new T_type_null(location) ;
return TRUE ;
}

void T_expression_null::generate(T_entity_program *program, FILE *file, int generate_type)
{
fprintf(file, "NULL") ;
}

// }{--------------------------------------------------------------

void T_expression_character::dump(FILE *file) const
{
fprintf(file, "%lu", value) ;
}

int T_expression_character::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
type = new T_type_identifier(location, program->character_class) ;
return TRUE ;
}

void T_expression_character::generate(T_entity_program *program, FILE *file, int generate_type)
{
fprintf(file, "CLASS_Character(%lu)", value) ;
}

// }{--------------------------------------------------------------

void T_expression_type::dump(FILE *file) const
{
type_value->dump(file) ;
}

int T_expression_type::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
type_value->verify_semantic(compiler, program, scope, method_type) ;
type = new T_type_identifier(location, program->type_class) ;
return TRUE ;
}

// }{--------------------------------------------------------------

void T_expression_vector::dump(FILE *file) const
{
fprintf(file, "[ ") ;
int first = TRUE ;
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	if (first) first = FALSE ; else fprintf(file, ", ") ;
	expression->dump(file) ;
	expression = expression->next ;
	}
fprintf(file, " ]") ;
}

void T_expression_vector::parse(T_entity_compiler *compiler)
{
for(;;)
	{
	if (compiler->current_item == entity_compiler_item_eof)
		{
		compiler->add_error(location, "vector unterminated.") ;
		return ;
		}
	if (compiler->current_item == entity_compiler_item_right_right_bracket)
		{
		compiler->next_item() ;
		return ;
		}
	T_expression *loc = compiler->parse_logical_or_expression() ;
	if (loc == NULL)
		{
		compiler->add_error(compiler->location, "expression expected.") ;
		if (!compiler->skip_comma())
			{
			if (compiler->current_item == entity_compiler_item_right_right_bracket) compiler->next_item() ;
			return ;
			}
		}
	else
		{
		expressions.insert(loc) ;
		if (compiler->current_item == entity_compiler_item_comma)
			{
			compiler->next_item() ;
			}
		else if (compiler->current_item != entity_compiler_item_right_right_bracket)
			{
			compiler->add_error(compiler->location, "comma expected.") ;
			}
		}
	}
}

int T_expression_vector::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
int result = TRUE ;
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	if (!expression->verify_semantic(compiler, program, scope, method_type)) result = FALSE ;
	expression = expression->next ;
	}
type = new T_type_vector(location) ;
return result ;
}

void T_expression_vector::prepare(T_entity_program *program, FILE *file)
{
index = program->get_next_index() ;
fprintf(file, "CLASS_Vector vector_%d ;\n", index) ;
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	int loc = program->get_next_index() ;
	expression->prepare(program, file) ;
	if (expression->type->is_reference())
		{
		fprintf(file, "vector_%d.add_item(", index) ;
		expression->generate(program, file, type_generate_class_reference) ;
		fprintf(file, ") ;\n") ;
		}
	else
		{
		expression->type->generate_type_name(file, type_generate_instance) ;
		fprintf(file, " local_%d ;\n", loc) ;
		fprintf(file, "local_%d = ", loc) ;
		expression->generate(program, file, type_generate_value) ;
		fprintf(file, " ;\n") ;
		fprintf(file, "vector_%d.add_item(&local_%d.data) ;\n", index, loc) ;
		}
	expression = expression->next ;
	}
}

void T_expression_vector::generate(T_entity_program *program, FILE *file, int generate_type)
{
fprintf(file, "vector_%d", index) ;
}

// }{--------------------------------------------------------------

void T_expression_native::dump(FILE *file) const
{
fprintf(file, "native ") ;
switch (type)
	{
	case expression_native_cpp: fprintf(file, "cpp ") ; break ;
	}
fprintf(file, "%s", value.string()) ;
}

void T_expression_native::parse(T_entity_compiler *compiler)
{
T_string_iterator start(compiler->location) ;
if (compiler->current_item != entity_compiler_item_left_brace)
	{
	compiler->add_error(compiler->location, "left brace expected.") ;
	return ;
	}
compiler->next_item() ;
if (parse_block(compiler))
	{
	T_string_iterator end(compiler->location) ;
	end.increment() ;
	value.set(start, end) ;
	compiler->next_item() ;
	}
}

int T_expression_native::parse_block(T_entity_compiler *compiler)
{
for(;;)
	{
	if (compiler->current_item == entity_compiler_item_eof)
		{
		compiler->add_error(location, "native unterminated.") ;
		return FALSE ;
		}
	if (compiler->current_item == entity_compiler_item_right_brace) return TRUE ;
	if (compiler->current_item == entity_compiler_item_left_brace)
		{
		compiler->next_item() ;
		if (!parse_block(compiler)) return FALSE ;
		}
	compiler->next_item() ;
	}
}

void T_expression_native::generate_instruction(T_entity_program *program, FILE *file)
{
if (type == expression_native_cpp) fprintf(file, "%s\n", value.string()) ;
else fprintf(file, "{}\n") ;
}

// }{--------------------------------------------------------------

void T_expression_local::dump(FILE *file) const
{
if (constant) fprintf(file, "const ") ;
else fprintf(file, "var ") ;
fprintf(file, "%s ", name.string()) ;
if (type_expression != NULL)
	{
	fprintf(file, " : ") ;
	type_expression->dump(file) ;
	}
if (expression != NULL)
	{
	fprintf(file, " = ") ;
	expression->dump(file) ;
	}
fprintf(file, "\n") ;
}

void T_expression_local::parse(T_entity_compiler *compiler)
{
if (!compiler->is_identifier())
	{
	compiler->add_error(compiler->location, "identifier expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
name.set(compiler->string) ;
compiler->next_item() ;
if (compiler->current_item == entity_compiler_item_colon)
	{
	compiler->next_item() ;
	type_expression = compiler->parse_logical_or_expression() ;
	if (type_expression == NULL)
		{
		compiler->add_error(compiler->location, "type expected.") ;
		compiler->skip_semicolon() ;
		return ;
		}
	}
if (compiler->current_item == entity_compiler_item_equal)
	{
	compiler->next_item() ;
	expression = compiler->parse_arithmetic_or_expression() ;
	if (expression == NULL)
		{
		compiler->add_error(compiler->location, "expression expected.") ;
		compiler->skip_semicolon() ;
		return ;
		}
	}
if ((type_expression == NULL) && (expression == NULL))
	{
	compiler->add_error(compiler->location, "colon or equal expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
}

int T_expression_local::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
//fprintf(stderr, "local %s : semantic\n", name.string()) ;
if (expression != NULL)
	{
	if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
	if (expression->type == NULL) { compiler->add_error(location, "bad expression %s (type NULL)", expression->get_name()) ; return FALSE ; }
//fprintf(stderr, "types=%d/%d\n", type_value->get_class(), expression->type->get_class()) ;
	}
if (type_expression == NULL)
	{
	type_value = expression->type ;
	}
else
	{
	if (!type_expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
	type_value = type_expression->get_type_expression() ;
//fprintf(stderr, "type : ") ; type_expression->dump(stderr) ; fprintf(stderr, "  type_value=%p\n", type_value) ;
	if (type_value == NULL)
		{
		compiler->add_error(location, "bad type for local.") ;
		return FALSE ;
		}
	if ((expression != NULL) && !type_value->is_good_for_call(program, expression->type))
		{
		compiler->add_error(location, "bad initialization.") ;
		return FALSE ;
		}
	}
T_scope *scope_loc = scope ;
for(;;)
	{
	if (scope_loc == NULL)
		{
		compiler->add_error(location, "local outside of block.") ;
		return FALSE ;
		}
	if (scope_loc->is_block())
		{
		((T_block_scope *)scope_loc)->locals.insert(new T_scope_local(this)) ;
		break ;
		}
	scope_loc = scope_loc->previous_scope ;
	}
type = new T_type_void(location) ;
return TRUE ;
}

void T_expression_local::generate_instruction(T_entity_program *program, FILE *file)
{
if (is_reference()) type_value->generate_type_name(file, type_generate_value) ;
else type_value->generate_type_name(file, type_generate_instance) ;
fprintf(file, " local_%s ;\n", name.string()) ;
if (expression != NULL)
	{
	expression->prepare(program, file) ;
	fprintf(file, "local_%s = ", name.string()) ;
	if (type_value->is_reference()) expression->generate(program, file, type_generate_class_reference) ;
	else expression->generate(program, file, type_generate_value) ;
	fprintf(file, " ;\n") ;
	}
else if (type_expression != NULL)
	{
	type_expression->generate_constructor(program, file, name) ;
	}
}

// }{--------------------------------------------------------------

void T_expression_new::dump(FILE *file) const
{
fprintf(file, "new %s {", name.string()) ;
T_expression *expression = expressions.first ;
if (expression != NULL)
	{
	for(;;)
		{
		expression->dump(file) ;
		expression = expression->next ;
		if (expression == NULL) break ;
		fprintf(file, ", ") ;
		}
	}
fprintf(file, "}") ;
}

void T_expression_new::parse(T_entity_compiler *compiler)
{
if (!compiler->is_identifier())
	{
	compiler->add_error(compiler->location, "identifier expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
name.set(compiler->string) ;
compiler->next_item() ;
if (compiler->current_item == entity_compiler_item_left_parenthesis)
	{
	compiler->next_item() ;
	if (compiler->current_item == entity_compiler_item_right_parenthesis)
		{
		compiler->next_item() ;
		}
	else
		{
		for(;;)
			{
			T_expression *loc = compiler->parse_logical_or_expression() ;
			if (loc == NULL)
				{
				compiler->add_error(compiler->location, "expression expected.") ;
				return ;
				}
			expressions.insert(loc) ;
			if (compiler->current_item == entity_compiler_item_right_parenthesis)
				{
				compiler->next_item() ;
				return ;
				}
			if (compiler->current_item != entity_compiler_item_comma)
				{
				compiler->add_error(compiler->location, "comma or right parenthesis expected.") ;
				return ;
				}
			compiler->next_item() ;
			}
		}
	}
}

int T_expression_new::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
object_class = program->search_class(name) ;
if (object_class == NULL)
	{
	compiler->add_error(location, "class not found.") ;
	return FALSE ;
	}
int ok = TRUE ;
T_expression *loc = expressions.first ;
while (loc != NULL)
	{
	if (!loc->verify_semantic(compiler, program, scope, method_type)) ok = FALSE ;
	loc = loc->next ;
	}
if (!ok) return FALSE ;
constructor = object_class->search_constructor(program, this) ;
if (constructor == NULL)
	{
	compiler->add_error(location, "constructor not found.") ;
	return FALSE ;
	}
type = new T_type_reference(location, TRUE, new T_type_identifier(location, object_class)) ;
return TRUE ;
}

void T_expression_new::prepare(T_entity_program *program, FILE *file)
{
T_expression *loc = expressions.first ;
while (loc != NULL)
	{
	loc->prepare(program, file) ;
	loc = loc->next ;
	}
index = program->get_next_index() ;
fprintf(file, "CLASS_%s *local_%d = &(new INSTANCE_%s)->data ;\n", object_class->name.string(), index, object_class->name.string()) ;
fprintf(file, "constructor_%p(local_%d", constructor, index) ;
T_prototype_argument *argument = constructor->prototype.arguments.first ;
if (argument != NULL) argument = argument->next ;
loc = expressions.first ;
while (argument != NULL)
	{
	if (strcmp(argument->name.string(), "self") == 0)
		{
//		fprintf(file, "(") ;
//		argument->type->generate_type_name(file, type_generate_class_reference) ;
//		fprintf(file, ")local_%d", index) ;
		}
	else if (loc != NULL)
		{
		fprintf(file, ", ") ;
		loc->generate(program, file, argument->is_reference ? type_generate_class_reference : type_generate_value) ;
		loc = loc->next ;
		}
	else
		{
		fprintf(file, ", ") ;
		fprintf(file, "empty_vector") ;
		}
	argument = argument->next ;
	}
fprintf(file, ") ;\n") ;
}

void T_expression_new::generate(T_entity_program *program, FILE *file, int generate_type)
{
if (generate_type == type_generate_value) fprintf(file, "*local_%d", index) ;
else fprintf(file, "local_%d", index) ;
}

// }{--------------------------------------------------------------

void T_expression_if::dump(FILE *file) const
{
int first = TRUE ;
T_expression_if_item *item = items.first ;
while (item != NULL)
	{
	if (first) first = FALSE ;
	else fprintf(file, "\nelse ") ;
	fprintf(file, "if (") ;
	item->condition->dump(file) ;
	fprintf(file, ")") ;
	item->expression->dump(file) ;
	item = item->next ;
	}
if (else_expression != NULL)
	{
	fprintf(file, "\nelse ") ;
	else_expression->dump(file) ;
	}
}

void T_expression_if::parse(T_entity_compiler *compiler)
{
for(;;)
	{
	compiler->parse_left_parenthesis() ;
	T_expression *condition = compiler->parse_expression() ;
	if (condition == NULL)
		{
		compiler->add_error(compiler->location, "condition expected.") ;
		compiler->skip_semicolon() ;
		}
	else
		{
		if (!compiler->parse_right_parenthesis())
			{
			compiler->add_error(compiler->location, "right parenthesis expected.") ;
			compiler->skip_semicolon() ;
			}
		else
			{
			T_expression *expression = compiler->parse_assign_expression() ;
			if (expression != NULL)
				{
				items.insert(new T_expression_if_item(condition, expression)) ;
				if (!expression->instruction && !expression->is_block())
					{
					if (compiler->current_item == entity_compiler_item_semicolon)
						{
						compiler->next_item() ;
						expression->instruction = TRUE ;
						}
/*					else if ((compiler->current_item != entity_compiler_item_right_brace) && (compiler->current_item != entity_compiler_item_comma))
						{
						compiler->add_error(compiler->location, "semicolon or comma expected.") ;
						}
*/
					}
				}
			}
		}
	if (!compiler->parse_keyword("else"))
		{
		instruction = (items.last != NULL) && items.last->expression->instruction ;
		return ;
		}
	if (!compiler->parse_keyword("if"))
		{
		else_expression = compiler->parse_expression() ;
		if (else_expression == NULL)
			{
			compiler->add_error(compiler->location, "expression expected.") ;
			compiler->skip_semicolon() ;
			}
		instruction = else_expression->instruction ;
		return ;
		}
	}
}

int T_expression_if::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
int ok = TRUE ;
dead = TRUE ;
T_expression_if_item *item = items.first ;
while (item != NULL)
	{
	if (!item->condition->verify_semantic(compiler, program, scope, method_type))
		{
		ok = FALSE ;
		}
	else if (!item->condition->test && !(*program->boolean_class->is_good_for_call)(program->boolean_class, program, item->condition->type))
		{
		compiler->add_error(item->condition->location, "boolean or test expected.") ;
		}
	if (!item->expression->verify_semantic(compiler, program, scope, method_type))
		{
		ok = FALSE ;
		}
	else
		{
		if (item->expression->test) compiler->add_error(item->expression->location, "test not expected here.") ;
		if (type == NULL) type = item->expression->type ;
		else type = type->highest_common_factor(compiler, program, item->expression->location, item->expression->type) ;
		if (!item->expression->dead) dead = FALSE ;
		}
	item = item->next ;
	}
if (type == NULL) type = new T_type_void(location) ;
if (else_expression == NULL)
	{
	dead = FALSE ;
	if (!type->is_void()) compiler->add_error(location, "else must be defined for non void if.") ;
	}
else
	{
	if (!else_expression->verify_semantic(compiler, program, scope, method_type))
		{
		ok = FALSE ;
		}
	else
		{
		if (else_expression->test) compiler->add_error(else_expression->location, "test not expected here.") ;
		type = type->highest_common_factor(compiler, program, else_expression->location, else_expression->type) ;
		if (!else_expression->dead) dead = FALSE ;
		}
	}
return ok ;
}

void T_expression_if::generate_instruction(T_entity_program *program, FILE *file)
{
int index_end = program->get_next_index() ;
T_expression_if_item *item = items.first ;
while (item != NULL)
	{
	fprintf(file, "{\n") ;
	int index_true = program->get_next_index() ;
	int index_false = program->get_next_index() ;
	item->condition->generate_test(program, file, false, index_true, index_false) ;
	fprintf(file, "label_%d:;\n", index_true) ;
	item->expression->generate_instruction(program, file) ;
	fprintf(file, "}\n") ;
	if (((item->next != NULL) || (else_expression != NULL)) && !item->expression->dead) fprintf(file, "goto label_%d ;\n", index_end) ;
	fprintf(file, "label_%d:;\n", index_false) ;
	item = item->next ;
	}
if (else_expression != NULL)
	{
	if (else_expression->is_block())
		{
		else_expression->generate_instruction(program, file) ;
		}
	else
		{
		fprintf(file, "{\n") ;
		else_expression->generate_instruction(program, file) ;
		fprintf(file, "}\n") ;
		}
	}
fprintf(file, "label_%d:;\n", index_end) ;
}

// }{--------------------------------------------------------------

void T_expression_loop::dump(FILE *file) const
{
fprintf(file, "loop ") ;
if (*name.string() != 0) fprintf(file, "%s ", name.string()) ;
expression->dump(file) ;
}

void T_expression_loop::parse(T_entity_compiler *compiler)
{
if (compiler->is_identifier())
	{
	name = compiler->string ;
	compiler->next_item() ;
	}
expression = compiler->parse_expression() ;
if (expression == NULL)
	{
	compiler->add_error(compiler->location, "expression expected.") ;
	compiler->skip_semicolon() ;
	}
}

int T_expression_loop::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
T_loop_scope scope_loc(scope, this) ;
if (!expression->verify_semantic(compiler, program, &scope_loc, method_type)) return FALSE ;
if (!expression->type->is_void()) compiler->add_error(expression->location, "expression must be void.") ;
type = new T_type_void(location) ;
dead = expression->dead ;
return TRUE ;
}

void T_expression_loop::generate_instruction(T_entity_program *program, FILE *file)
{
fprintf(file, "for(;;)\n") ;
fprintf(file, "{\n") ;
expression->generate_instruction(program, file) ;
fprintf(file, "}\n") ;
}

// }{--------------------------------------------------------------

void T_expression_while::dump(FILE *file) const
{
fprintf(file, "while ") ;
condition->dump(file) ;
fprintf(file, " do ") ;
if (*name.string() != 0) fprintf(file, "%s ", name.string()) ;
expression->dump(file) ;
}

void T_expression_while::parse(T_entity_compiler *compiler)
{
condition = compiler->parse_expression() ;
if (condition == NULL)
	{
	compiler->add_error(compiler->location, "condition expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
if (!compiler->parse_keyword("do"))
	{
	compiler->add_error(compiler->location, "keyword do expected.") ;
	compiler->skip_semicolon() ;
	return ;
	}
if (compiler->is_identifier())
	{
	name = compiler->string ;
	compiler->next_item() ;
	}
expression = compiler->parse_expression() ;
if (expression == NULL)
	{
	compiler->add_error(compiler->location, "expression expected.") ;
	compiler->skip_semicolon() ;
	}
}

int T_expression_while::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
index = program->get_next_index() ;
if (condition->verify_semantic(compiler, program, scope, method_type))
	{
	if (!condition->test && !(*program->boolean_class->is_good_for_call)(program->boolean_class, program, condition->type))
		{
		compiler->add_error(condition->location, "boolean expected.") ;
		}
	}
return T_expression_loop::verify_semantic(compiler, program, scope, method_type) ;
}

void T_expression_while::generate_instruction(T_entity_program *program, FILE *file)
{
fprintf(file, "for(;;)\n") ;
fprintf(file, "{\n") ;
condition->generate_test(program, file, FALSE, index, 0) ;
fprintf(file, "label_%d:;\n", index) ;
expression->generate_instruction(program, file) ;
fprintf(file, "}\n") ;
}

// }{--------------------------------------------------------------

void T_expression_leave::dump(FILE *file) const
{
fprintf(file, "leave ") ;
if (*name.string() != 0) fprintf(file, "%s ", name.string()) ;
if (expression != NULL)
	{
	fprintf(file, "with ") ;
	expression->dump(file) ;
	}
}

void T_expression_leave::parse(T_entity_compiler *compiler)
{
if (compiler->parse_keyword("with"))
	{
	expression = compiler->parse_expression() ;
	if (expression == NULL)
		{
		compiler->add_error(compiler->location, "expression expected.") ;
		compiler->skip_semicolon() ;
		}
	}
else if (compiler->is_identifier())
	{
	name = compiler->string ;
	compiler->next_item() ;
	if (compiler->parse_keyword("with"))
		{
		expression = compiler->parse_expression() ;
		if (expression == NULL)
			{
			compiler->add_error(compiler->location, "expression expected.") ;
			compiler->skip_semicolon() ;
			}
		}
	}
}

int T_expression_leave::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
T_scope *loc = scope ;
for(;;)
	{
	if (loc == NULL)
		{
		if (*name.string() != 0) compiler->add_error(location, "loop %s not found in scope.", name.string()) ;
		else compiler->add_error(location, "no loop in scope.") ;
		return FALSE ;
		}
	if (loc->is_loop())
		{
		if ((*name.string() == 0) || (strcmp(name.string(), ((T_loop_scope *)loc)->loop->name.string()) == 0)) break ;
		}
	loc = loc->previous_scope ;
	}
if (expression != NULL) compiler->add_error(location, "NI loop with value.") ;
type = new T_type_void(location) ;
return TRUE ;
}

void T_expression_leave::generate_instruction(T_entity_program *program, FILE *file)
{
fprintf(file, "break ;\n") ;
}

// }{--------------------------------------------------------------

void T_expression_return::dump(FILE *file) const
{
fprintf(file, "return ") ;
if (expression != NULL)
	{
	fprintf(file, "with ") ;
	expression->dump(file) ;
	}
}

void T_expression_return::parse(T_entity_compiler *compiler)
{
if (compiler->parse_keyword("with"))
	{
	expression = compiler->parse_expression() ;
	if (expression == NULL)
		{
		compiler->add_error(compiler->location, "expression expected.") ;
		compiler->skip_semicolon() ;
		}
	}
}

int T_expression_return::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (method_type == NULL)
	{
	compiler->add_error(location, "Return not expected here.") ;
	return FALSE ;
	}
dead = TRUE ;
type = new T_type_void(location) ;
if (expression == NULL) return TRUE ;
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
if (expression->dead || expression->type->is_void())
	{
	compiler->add_error(location, "Expression expected for return.") ;
	return FALSE ;
	}
if (expression->test)
	{
	compiler->add_error(location, "test not expected here.") ;
	return FALSE ;
	}
method_returned_type = method_type->returned_type ;
return compiler->can_assign_to(expression->type, method_type->returned_type) ;
}

void T_expression_return::generate_instruction(T_entity_program *program, FILE *file)
{
if (expression != NULL)
	{
	expression->prepare(program, file) ;
	fprintf(file, "return ") ;
	if (method_returned_type->is_reference())
		{
		fprintf(file, "(") ;
		method_returned_type->generate_type_name(file, type_generate_value) ;
		fprintf(file, ")") ;
		expression->generate(program, file, type_generate_class_reference) ;
		}
	else
		{
		expression->generate(program, file, type_generate_value) ;
		}
	fprintf(file, " ;\n") ;
	}
else
	{
	fprintf(file, "return ;\n") ;
	}
}

// }{--------------------------------------------------------------

void T_expression_compute::dump(FILE *file) const
{
fprintf(file, "compute (") ;
value->dump(file) ;
fprintf(file, ")") ;
expression->dump(file) ;
}

void T_expression_compute::parse(T_entity_compiler *compiler)
{
compiler->parse_left_parenthesis() ;
value = compiler->parse_expression() ;
if (value == NULL)
	{
	compiler->add_error(compiler->location, "value expected.") ;
	compiler->skip_semicolon() ;
	}
else
	{
	if (!compiler->parse_right_parenthesis())
		{
		compiler->add_error(compiler->location, "right parenthesis expected.") ;
		compiler->skip_semicolon() ;
		}
	else
		{
		expression = compiler->parse_expression() ;
		if (expression == NULL)
			{
			compiler->add_error(compiler->location, "expression expected.") ;
			compiler->skip_semicolon() ;
			}
		}
	}
}

int T_expression_compute::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!value->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
type = new T_type_void(location) ;
T_compute_scope scope_loc(scope, this) ;
if (!expression->verify_semantic(compiler, program, &scope_loc, method_type)) return FALSE ;
return TRUE ;
}

void T_expression_compute::generate_instruction(T_entity_program *program, FILE *file)
{
index = program->get_next_index() ;
value->prepare(program, file) ;
value->type->generate_type_name(file, type_generate_value) ;
fprintf(file, " compute_%d = ", index) ;
value->generate(program, file, type_generate_value) ;
fprintf(file, " ;\n") ;
expression->generate_instruction(program, file) ;
}

// }{--------------------------------------------------------------

void T_expression_case::dump(FILE *file) const
{
fprintf(file, "case ") ;
expression->dump(file) ;
}

void T_expression_case::parse(T_entity_compiler *compiler)
{
expression = compiler->parse_arithmetic_or_expression() ;
if (expression == NULL)
	{
	compiler->add_error(compiler->location, "expression expected.") ;
	compiler->skip_semicolon() ;
	}
}

int T_expression_case::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
T_scope *loc = scope ;
for(;;)
	{
	if (loc == NULL)
		{
		compiler->add_error(location, "no compute in scope.") ;
		return FALSE ;
		}
	if (loc->is_compute()) break ;
	loc = loc->previous_scope ;
	}
compute = ((T_compute_scope *)loc)->compute ;
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
if (expression->test) compiler->add_error(expression->location, "test not expected here.") ;
/*if (!compute->value->type->is_good_for_call(program, expression->type) && !expression->type->is_good_for_call(program, compute->value->type))
	{
	compiler->add_error(location, "type are not compatible for comparison.") ;
	}
*/
type = new T_type_void(location) ;
test = TRUE ;
return TRUE ;
}

void T_expression_case::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
int label ;
expression->prepare(program, file) ;
fprintf(file, "if (compute_%d", compute->index) ;
if (jump_if_true)
	{
	label = true_label ;
	fprintf(file, " == ") ;
	}
else
	{
	label = false_label ;
	fprintf(file, " != ") ;
	}
expression->generate(program, file, type_generate_value) ;
fprintf(file, ")") ;
if (label == 0) fprintf(file, " break ;\n") ;
else fprintf(file, " goto label_%d ;\n", label) ;
}

// }{--------------------------------------------------------------

void T_expression_test_or::dump(FILE *file) const
{
T_expression *expression = expressions.first ;
for(;;)
	{
	expression->dump(file) ;
	expression = expression->next ;
	if (expression == NULL) break ;
	fprintf(file, " || ") ;
	}
}

int T_expression_test_or::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
int ok = TRUE ;
dead = TRUE ;
T_block_scope scope_loc(scope) ;
T_expression *expression = expressions.first ;
if (!expression->verify_semantic(compiler, program, &scope_loc, method_type)) ok = FALSE ;
test = expression->test ;
if (!expression->dead) dead = FALSE ;
type = expression->type ;
for(;;)
	{
	expression = expression->next ;
	if (expression == NULL) break ;
	T_block_scope scope_loc(scope) ;
	if (!expression->verify_semantic(compiler, program, &scope_loc, method_type))
		{
		ok = FALSE ;
		}
	else
		{
		test = expression->test ;
		if (!expression->dead) dead = FALSE ;
		type = type->highest_common_factor(compiler, program, expression->location, expression->type) ;
		}
	}
return ok ;
}

void T_expression_test_or::generate_instruction(T_entity_program *program, FILE *file)
{
int index_end = program->get_next_index() ;
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	fprintf(file, "{\n") ;
	int index = program->get_next_index() ;
	if (expression->test) expression->generate_test(program, file, TRUE, index_end, (expression->next == NULL) ? index_end : index) ;
	else expression->generate_instruction(program, file) ;
	fprintf(file, "}\n") ;
	if (expression->next != NULL) fprintf(file, "label_%d:;\n", index) ;
	expression = expression->next ;
	}
if (!dead) fprintf(file, "label_%d:;\n", index_end) ;
}

void T_expression_test_or::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
T_expression *expression = expressions.first ;
while (expression->next != NULL)
	{
	fprintf(file, "{\n") ;
	int index = program->get_next_index() ;
	if (expression->test) expression->generate_test(program, file, TRUE, true_label, index) ;
	else expression->generate_instruction(program, file) ;
	fprintf(file, "}\n") ;
	fprintf(file, "label_%d:;\n", index) ;
	expression = expression->next ;
	}
if (expression->test) expression->generate_test(program, file, jump_if_true, true_label, false_label) ;
else expression->generate_instruction(program, file) ;
}

// }{--------------------------------------------------------------

void T_expression_test_and::dump(FILE *file) const
{
T_expression *expression = expressions.first ;
for(;;)
	{
	expression->dump(file) ;
	expression = expression->next ;
	if (expression == NULL) break ;
	fprintf(file, ", ") ;
	}
}

int T_expression_test_and::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
int result = TRUE ;
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	if (dead)
		{
		compiler->add_error(expression->location, "Unreachable code.") ;
		result = FALSE ;
		}
	if (!expression->verify_semantic(compiler, program, scope, method_type))
		{
		result = FALSE ;
		}
	else
		{
		type = expression->type ;
		if (expression->dead) dead = TRUE ;
		if (expression->test) test = TRUE ;
		if (type == NULL)
			{
			compiler->add_error(expression->location, "type NULL for %s", expression->get_name()) ;
			}
		else if (!type->is_void() && (expression->next != NULL))
			{
			compiler->add_error(expression->location, "test and : No value expected here (%s).", expression->get_name()) ;
			result = FALSE ;
			}
		}
	expression = expression->next ;
	}
return result ;
}

void T_expression_test_and::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	if (expression->test)
		{
		int index = program->get_next_index() ;
		expression->generate_test(program, file, FALSE, index, false_label) ;
		}
	else
		{
		expression->generate_instruction(program, file) ;
		}
	expression = expression->next ;
	}
if (jump_if_true && !dead)
	{
	if (true_label == 0) fprintf(file, "break ;\n") ;
	else fprintf(file, "goto label_%d ;\n", true_label) ;
	}
}

void T_expression_test_and::generate_instruction(T_entity_program *program, FILE *file)
{
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	expression->generate_instruction(program, file) ;
	expression = expression->next ;
	}
}

// }{--------------------------------------------------------------

void T_expression_test::dump(FILE *file) const
{
fprintf(file, "?") ;
expression->dump(file) ;
}

int T_expression_test::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
if (!expression->test && !(*program->boolean_class->is_good_for_call)(program->boolean_class, program, expression->type))
	{
	compiler->add_error(expression->location, "boolean or test expected.") ;
	}
type = new T_type_void(location) ;
test = TRUE ;
return TRUE ;
}

void T_expression_test::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
fprintf(file, "//test : generate_test\n") ;
expression->generate_test(program, file, jump_if_true, true_label, false_label) ;
}

// }{--------------------------------------------------------------

void T_expression_success::dump(FILE *file) const
{
fprintf(file, "success") ;
}

int T_expression_success::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
type = new T_type_void(location) ;
test = TRUE ;
return TRUE ;
}

void T_expression_success::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
fprintf(file, "//success : generate_test\n") ;
if (jump_if_true)
	{
	if (true_label == 0) fprintf(file, "break ;\n") ;
	else fprintf(file, "goto label_%d ;\n", true_label) ;
	}
}

// }{--------------------------------------------------------------

void T_expression_assign::dump(FILE *file) const
{
destination->dump(file) ;
switch (assign_type)
	{
	case expression_assign_type_assign: fprintf(file, " = ") ; break ;
	case expression_assign_type_add: fprintf(file, " += ") ; break ;
	case expression_assign_type_substract: fprintf(file, " -= ") ; break ;
	case expression_assign_type_multiply: fprintf(file, " *= ") ; break ;
	case expression_assign_type_divide: fprintf(file, " /= ") ; break ;
	case expression_assign_type_modulo: fprintf(file, " %%= ") ; break ;
	case expression_assign_type_and: fprintf(file, " &= ") ; break ;
	case expression_assign_type_exclusive_or: fprintf(file, " ^= ") ; break ;
	case expression_assign_type_or: fprintf(file, " |= ") ; break ;
	case expression_assign_type_left_shift: fprintf(file, " <<= ") ; break ;
	case expression_assign_type_right_shift: fprintf(file, " >>= ") ; break ;
	}
expression->dump(file) ;
}

int T_expression_assign::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
if (!destination->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
type = new T_type_void(location) ;
return TRUE ;
}

void T_expression_assign::prepare(T_entity_program *program, FILE *file)
{
expression->prepare(program, file) ;
destination->prepare(program, file) ;
}

void T_expression_assign::generate_instruction(T_entity_program *program, FILE *file)
{
expression->prepare(program, file) ;
destination->prepare(program, file) ;
if (destination->type->is_reference())
	{
	destination->generate(program, file, type_generate_class_reference) ;
	switch (assign_type)
		{
		case expression_assign_type_assign: fprintf(file, " = ") ; break ;
		case expression_assign_type_add: fprintf(file, " += ") ; break ;
		case expression_assign_type_substract: fprintf(file, " -= ") ; break ;
		case expression_assign_type_multiply: fprintf(file, " *= ") ; break ;
		case expression_assign_type_divide: fprintf(file, " /= ") ; break ;
		case expression_assign_type_modulo: fprintf(file, " %%= ") ; break ;
		case expression_assign_type_and: fprintf(file, " &= ") ; break ;
		case expression_assign_type_exclusive_or: fprintf(file, " ^= ") ; break ;
		case expression_assign_type_or: fprintf(file, " |= ") ; break ;
		case expression_assign_type_left_shift: fprintf(file, " <<= ") ; break ;
		case expression_assign_type_right_shift: fprintf(file, " >>= ") ; break ;
		}
	expression->generate(program, file, type_generate_class_reference) ;
	fprintf(file, " ;\n") ;
	}
else
	{
	destination->generate(program, file, type_generate_value) ;
	switch (assign_type)
		{
		case expression_assign_type_assign: fprintf(file, " = ") ; break ;
		case expression_assign_type_add: fprintf(file, " += ") ; break ;
		case expression_assign_type_substract: fprintf(file, " -= ") ; break ;
		case expression_assign_type_multiply: fprintf(file, " *= ") ; break ;
		case expression_assign_type_divide: fprintf(file, " /= ") ; break ;
		case expression_assign_type_modulo: fprintf(file, " %%= ") ; break ;
		case expression_assign_type_and: fprintf(file, " &= ") ; break ;
		case expression_assign_type_exclusive_or: fprintf(file, " ^= ") ; break ;
		case expression_assign_type_or: fprintf(file, " |= ") ; break ;
		case expression_assign_type_left_shift: fprintf(file, " <<= ") ; break ;
		case expression_assign_type_right_shift: fprintf(file, " >>= ") ; break ;
		}
	expression->generate(program, file, type_generate_value) ;
	fprintf(file, " ;\n") ;
	}
}

// }{--------------------------------------------------------------

void T_expression_logical_or::dump(FILE *file) const
{
T_expression *expression = expressions.first ;
for(;;)
	{
	expression->dump(file) ;
	expression = expression->next ;
	if (expression == NULL) break ;
	fprintf(file, " or ") ;
	}
}

int T_expression_logical_or::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
int ok = TRUE ;
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	if (!expression->verify_semantic(compiler, program, scope, method_type))
		{
		ok = FALSE ;
		}
	else if (!expression->test && !(*program->boolean_class->is_good_for_call)(program->boolean_class, program, expression->type))
		{
		ok = FALSE ;
		compiler->add_error(expression->location, "boolean or test expected.") ;
		}
	expression = expression->next ;
	}
type = new T_type_identifier(location, program->boolean_class) ;
return ok ;
}

void T_expression_logical_or::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
T_expression *expression = expressions.first ;
while (expression->next != NULL)
	{
	int index = program->get_next_index() ;
	fprintf(file, "{\n") ;
	expression->generate_test(program, file, TRUE, true_label, index) ;
	fprintf(file, "}\n") ;
	fprintf(file, "label_%d:;\n", index) ;
	expression = expression->next ;
	}
fprintf(file, "{\n") ;
expression->generate_test(program, file, jump_if_true, true_label, false_label) ;
fprintf(file, "}\n") ;
}

// }{--------------------------------------------------------------

void T_expression_logical_and::dump(FILE *file) const
{
T_expression *expression = expressions.first ;
for(;;)
	{
	expression->dump(file) ;
	expression = expression->next ;
	if (expression == NULL) break ;
	fprintf(file, " and ") ;
	}
}

int T_expression_logical_and::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
int ok = TRUE ;
T_expression *expression = expressions.first ;
while (expression != NULL)
	{
	if (!expression->verify_semantic(compiler, program, scope, method_type))
		{
		ok = FALSE ;
		}
	else if (!expression->test && !(*program->boolean_class->is_good_for_call)(program->boolean_class, program, expression->type))
		{
		ok = FALSE ;
		compiler->add_error(expression->location, "boolean or test expected.") ;
		}
	expression = expression->next ;
	}
type = new T_type_identifier(location, program->boolean_class) ;
return ok ;
}

void T_expression_logical_and::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
T_expression *expression = expressions.first ;
while (expression->next != NULL)
	{
	int index = program->get_next_index() ;
	fprintf(file, "{\n") ;
	expression->generate_test(program, file, FALSE, index, false_label) ;
	fprintf(file, "label_%d:;\n", index) ;
	fprintf(file, "}\n") ;
	expression = expression->next ;
	}
fprintf(file, "{\n") ;
expression->generate_test(program, file, jump_if_true, true_label, false_label) ;
fprintf(file, "}\n") ;
}

// }{--------------------------------------------------------------

void T_expression_comparison::dump(FILE *file) const
{
left->dump(file) ;
switch (comparison_type)
	{
	case expression_comparison_type_equal: fprintf(file, " == ") ; break ;
	case expression_comparison_type_not_equal: fprintf(file, " != ") ; break ;
	case expression_comparison_type_less: fprintf(file, " < ") ; break ;
	case expression_comparison_type_less_or_equal: fprintf(file, " <= ") ; break ;
	case expression_comparison_type_greater: fprintf(file, " > ") ; break ;
	case expression_comparison_type_greater_or_equal: fprintf(file, " >= ") ; break ;
	}
right->dump(file) ;
}

int T_expression_comparison::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
int ok = TRUE ;
if (!left->verify_semantic(compiler, program, scope, method_type)) ok = FALSE ;
if (!right->verify_semantic(compiler, program, scope, method_type)) ok = FALSE ;
if (ok)
	{
	if (left->test) compiler->add_error(left->location, "test not expected here.") ;
	if (right->test) compiler->add_error(right->location, "test not expected here.") ;
/*
	if (!left->type->is_good_for_call(program, right->type) && !right->type->is_good_for_call(program, left->type))
		{
		compiler->add_error(location, "type are not compatible for comparison.") ;
		}
// */
	}
type = new T_type_identifier(location, program->boolean_class) ;
return TRUE ;
}

void T_expression_comparison::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
int label ;
left->prepare(program, file) ;
right->prepare(program, file) ;
fprintf(file, "if (") ;
if (left->type->is_reference()) left->generate(program, file, type_generate_class_reference) ;
else left->generate(program, file, type_generate_value) ;
if (jump_if_true)
	{
	label = true_label ;
	switch (comparison_type)
		{
		case expression_comparison_type_equal: fprintf(file, " == ") ; break ;
		case expression_comparison_type_not_equal: fprintf(file, " != ") ; break ;
		case expression_comparison_type_less: fprintf(file, " < ") ; break ;
		case expression_comparison_type_less_or_equal: fprintf(file, " <= ") ; break ;
		case expression_comparison_type_greater: fprintf(file, " > ") ; break ;
		case expression_comparison_type_greater_or_equal: fprintf(file, " >= ") ; break ;
		}
	}
else
	{
	label = false_label ;
	switch (comparison_type)
		{
		case expression_comparison_type_equal: fprintf(file, " != ") ; break ;
		case expression_comparison_type_not_equal: fprintf(file, " == ") ; break ;
		case expression_comparison_type_less: fprintf(file, " >= ") ; break ;
		case expression_comparison_type_less_or_equal: fprintf(file, " > ") ; break ;
		case expression_comparison_type_greater: fprintf(file, " <= ") ; break ;
		case expression_comparison_type_greater_or_equal: fprintf(file, " < ") ; break ;
		}
	}
if (right->type->is_reference()) right->generate(program, file, type_generate_class_reference) ;
else right->generate(program, file, type_generate_value) ;
fprintf(file, ")") ;
if (label == 0) fprintf(file, " break ;\n") ;
else fprintf(file, " goto label_%d ;\n", label) ;
}

// }{--------------------------------------------------------------

void T_expression_arithmetic_or::dump(FILE *file) const
{
T_expression *expression = expressions.first ;
for(;;)
	{
	expression->dump(file) ;
	expression = expression->next ;
	if (expression == NULL) break ;
	fprintf(file, " | ") ;
	}
}

// }{--------------------------------------------------------------

void T_expression_arithmetic_xor::dump(FILE *file) const
{
T_expression *expression = expressions.first ;
for(;;)
	{
	expression->dump(file) ;
	expression = expression->next ;
	if (expression == NULL) break ;
	fprintf(file, " ^ ") ;
	}
}

// }{--------------------------------------------------------------

void T_expression_arithmetic_and::dump(FILE *file) const
{
T_expression *expression = expressions.first ;
for(;;)
	{
	expression->dump(file) ;
	expression = expression->next ;
	if (expression == NULL) break ;
	fprintf(file, " & ") ;
	}
}

// }{--------------------------------------------------------------

void T_expression_shift_left::dump(FILE *file) const
{
left->dump(file) ;
fprintf(file, " << ") ;
right->dump(file) ;
}

// }{--------------------------------------------------------------

void T_expression_shift_right::dump(FILE *file) const
{
left->dump(file) ;
fprintf(file, " >> ") ;
right->dump(file) ;
}

// }{--------------------------------------------------------------

void T_expression_additive::dump(FILE *file) const
{
expression->dump(file) ;
T_expression_additive_item *item = items.first ;
while (item != NULL)
	{
	switch (item->type)
		{
		case expression_additive_type_addition: fprintf(file, " + ") ; break ;
		case expression_additive_type_substraction: fprintf(file, " - ") ; break ;
		}
	item->expression->dump(file) ;
	item = item->next ;
	}
}

int T_expression_additive::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
type = expression->type ;
T_expression_additive_item *item = items.first ;
while (item != NULL)
	{
	if (!item->expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
	if (program->is_character(type))
		{
		if (item->type == expression_additive_type_addition)
			{
			if (!program->is_integer(item->expression->type))
				{
				compiler->add_error(item->expression->location, "integer expected.") ;
				return FALSE ;
				}
			}
		else
			{
			if (program->is_integer(item->expression->type))
				{
				}
			else if (program->is_character(item->expression->type))
				{
				type = new T_type_identifier(item->expression->location, program->integer_32_class) ;
				}
			else
				{
				compiler->add_error(item->expression->location, "integer or character expected.") ;
				return FALSE ;
				}
			}
		}
	else if (program->is_integer(type))
		{
		if (!program->is_integer(item->expression->type))
			{
			compiler->add_error(item->expression->location, "integer expected.") ;
			return FALSE ;
			}
		}
	item = item->next ;
	}
return TRUE ;
}

void T_expression_additive::prepare(T_entity_program *program, FILE *file)
{
expression->prepare(program, file) ;
T_expression_additive_item *item = items.first ;
while (item != NULL)
	{
	item->expression->prepare(program, file) ;
	item = item->next ;
	}
}

void T_expression_additive::generate(T_entity_program *program, FILE *file, int generate_type)
{
fprintf(file, "(") ;
expression->generate(program, file, type_generate_value) ;
T_expression_additive_item *item = items.first ;
while (item != NULL)
	{
	switch (item->type)
		{
		case expression_additive_type_addition: fprintf(file, " + ") ; break ;
		case expression_additive_type_substraction: fprintf(file, " - ") ; break ;
		}
	item->expression->generate(program, file, type_generate_value) ;
	item = item->next ;
	}
fprintf(file, ")") ;
}

// }{--------------------------------------------------------------

void T_expression_multiplicative::dump(FILE *file) const
{
expression->dump(file) ;
T_expression_multiplicative_item *item = items.first ;
while (item != NULL)
	{
	switch (item->type)
		{
		case expression_multiplicative_type_multiplication: fprintf(file, " * ") ; break ;
		case expression_multiplicative_type_division: fprintf(file, " / ") ; break ;
		case expression_multiplicative_type_modulus: fprintf(file, " %% ") ; break ;
		}
	item->expression->dump(file) ;
	item = item->next ;
	}
}

int T_expression_multiplicative::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
type = expression->type ;
T_expression_multiplicative_item *item = items.first ;
while (item != NULL)
	{
	if (!item->expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
	if (program->is_number(type))
		{
		if (!program->is_number(item->expression->type))
			{
			compiler->add_error(item->expression->location, "number expected.") ;
			return FALSE ;
			}
		}
	item = item->next ;
	}
return TRUE ;
}

void T_expression_multiplicative::prepare(T_entity_program *program, FILE *file)
{
expression->prepare(program, file) ;
T_expression_multiplicative_item *item = items.first ;
while (item != NULL)
	{
	item->expression->prepare(program, file) ;
	item = item->next ;
	}
}

void T_expression_multiplicative::generate(T_entity_program *program, FILE *file, int generate_type)
{
fprintf(file, "(") ;
expression->generate(program, file, type_generate_value) ;
T_expression_multiplicative_item *item = items.first ;
while (item != NULL)
	{
	switch (item->type)
		{
		case expression_multiplicative_type_multiplication: fprintf(file, " * ") ; break ;
		case expression_multiplicative_type_division: fprintf(file, " / ") ; break ;
		case expression_multiplicative_type_modulus: fprintf(file, " %% ") ; break ;
		}
	item->expression->generate(program, file, type_generate_value) ;
	item = item->next ;
	}
fprintf(file, ")") ;
}

// }{--------------------------------------------------------------

void T_expression_logical_not::dump(FILE *file) const
{
fprintf(file, " not ") ;
expression->dump(file) ;
}

int T_expression_logical_not::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
if (!expression->test && !(*program->boolean_class->is_good_for_call)(program->boolean_class, program, expression->type))
	{
	compiler->add_error(expression->location, "boolean or test expected.") ;
	return FALSE ;
	}
type = new T_type_identifier(location, program->boolean_class) ;
return TRUE ;
}

void T_expression_logical_not::prepare(T_entity_program *program, FILE *file)
{
expression->prepare(program, file) ;
}

void T_expression_logical_not::generate(T_entity_program *program, FILE *file, int generate_type)
{
fprintf(file, "!(") ;
expression->generate(program, file, generate_type) ;
fprintf(file, ")") ;
}

void T_expression_logical_not::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
expression->generate_test(program, file, !jump_if_true, false_label, true_label) ;
}

// }{--------------------------------------------------------------

void T_expression_bitwise_complement::dump(FILE *file) const
{
fprintf(file, " ~ ") ;
expression->dump(file) ;
}

// }{--------------------------------------------------------------

void T_expression_pre_increment::dump(FILE *file) const
{
fprintf(file, " ++") ;
expression->dump(file) ;
}

// }{--------------------------------------------------------------

void T_expression_pre_decrement::dump(FILE *file) const
{
fprintf(file, " --") ;
expression->dump(file) ;
}

// }{--------------------------------------------------------------

void T_expression_minus::dump(FILE *file) const
{
fprintf(file, " -") ;
expression->dump(file) ;
}

int T_expression_minus::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
if (!program->is_number(expression->type))
	{
	compiler->add_error(location, "Bad type for unary -") ;
	return FALSE ;
	}
type = expression->type ;
return TRUE ;
}

void T_expression_minus::prepare(T_entity_program *program, FILE *file)
{
expression->prepare(program, file) ;
}

void T_expression_minus::generate(T_entity_program *program, FILE *file, int generate_type)
{
fprintf(file, "-") ;
expression->generate(program, file, type_generate_value) ;
}

// }{--------------------------------------------------------------

void T_expression_plus::dump(FILE *file) const
{
fprintf(file, " +") ;
expression->dump(file) ;
}

// }{--------------------------------------------------------------

void T_expression_address::dump(FILE *file) const
{
fprintf(file, " &") ;
expression->dump(file) ;
}

int T_expression_address::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
type = new T_type_reference(location, TRUE, expression->type) ;
return TRUE ;
}

void T_expression_address::prepare(T_entity_program *program, FILE *file)
{
expression->prepare(program, file) ;
}

void T_expression_address::generate(T_entity_program *program, FILE *file, int generate_type)
{
expression->generate(program, file, type_generate_class_reference) ;
}

// }{--------------------------------------------------------------

void T_expression_identifier_access::dump(FILE *file) const
{
expression->dump(file) ;
fprintf(file, ".%s", identifier.string()) ;
}

int T_expression_identifier_access::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
if (expression->type == NULL)
	{
	compiler->add_error(location, "expression %s : type NULL.", expression->get_name()) ;
	return FALSE ;
	}
if (introspect)
	{
	if (strcmp(identifier.string(), "class") == 0)
		{
		type = new T_type_reference(location, TRUE, new T_type_identifier(location, program->object_class_class)) ;
		return TRUE ;
		}
	field = program->object_class_class->search_field(program, identifier) ;
	if (field == NULL)
		{
		compiler->add_error(location, "introspect field %s not found.", identifier.string()) ;
		return FALSE ;
		}
	type = field->type ;
	return TRUE ;
	}
if (!expression->search_field(program, identifier, this))
	{
	compiler->add_error(location, "bad access to %s.", identifier.string()) ;
	return FALSE ;
	}
return TRUE ;
}

int T_expression_identifier_access::verify_call_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type, T_expression_call_access *call)
{
index = program->get_next_index() ;
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
//fprintf(stderr, "%p : expression %p type=%p\n", this, expression, expression->type) ;
if (expression->type == NULL)
	{
	compiler->add_error(location, "bad type for call access to %s.", identifier.string()) ;
	return FALSE ;
	}
if (!introspect)
	{
	if (strcmp(identifier.string(), "duplicate") == 0)
		{
		introspect = TRUE ;
		T_object_class_method *loc = new T_object_class_method(program->class_class, location, FALSE, FALSE, FALSE, identifier) ;
		loc->type = new T_type_method(location, FALSE) ;
		T_prototype_argument *argument = new T_prototype_argument(location, "self") ;
		argument->type = new T_type_identifier(location, program->object_class_class) ;
		argument->is_reference = TRUE ;
		loc->type->prototype.arguments.insert(argument) ;
		loc->type->returned_type = expression->type ;
		method = loc ;
		}
	else
		{
		method = expression->type->search_call(program, TRUE, identifier, call) ;
		}
	}
//fprintf(stderr, "type=%d => method=%p\n", expression->type->get_class(), method) ;
if (method == NULL)
	{
	compiler->add_error(call->location, "bad call to %s.", identifier.string()) ;
	return FALSE ;
	}
type = method->type->returned_type ;
test = method->type->test ;
return TRUE ;
}

void T_expression_identifier_access::prepare(T_entity_program *program, FILE *file)
{
expression->prepare(program, file) ;
}

void T_expression_identifier_access::generate(T_entity_program *program, FILE *file, int generate_type)
{
if (introspect)
	{
	fprintf(file, "((") ;
	expression->type->generate_type_name(file, type_generate_header_reference) ;
	fprintf(file, ")") ;
	expression->generate(program, file, type_generate_class_reference) ;
	if (field == NULL) fprintf(file, ")[-1].introspect") ;
	else fprintf(file, ")[-1].introspect->_%s", identifier.string()) ;
	}
else if (field != NULL)
	{
	switch (generate_type)
		{
		case type_generate_value:
			expression->generate(program, file, type_generate_class_reference) ;
			fprintf(file, "->_%s", field->name.string()) ;
			break ;
		case type_generate_class_reference:
			if (type->is_reference())
				{
				expression->generate(program, file, type_generate_class_reference) ;
				fprintf(file, "->_%s", field->name.string()) ;
				}
			else
				{
				fprintf(file, "(&(") ;
				expression->generate(program, file, type_generate_class_reference) ;
				fprintf(file, "->_%s))", field->name.string()) ;
				}
			break ;
		}
	}
if (value != NULL)
	{
	fprintf(file, "%d", value->value) ;
	}
}

void T_expression_identifier_access::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
int label = jump_if_true ? true_label : false_label ;
expression->prepare(program, file) ;
if (jump_if_true) fprintf(file, "if (test(") ;
else fprintf(file, "if (!test(") ;
expression->generate(program, file, type_generate_class_reference) ;
fprintf(file, "->_%s", identifier.string()) ;
fprintf(file, "))") ;
if (label == 0) fprintf(file, " break ;\n") ;
else fprintf(file, " goto label_%d ;\n", label) ;
}

void T_expression_identifier_access::prepare_call(T_entity_program *program, FILE *file, const T_expression_call_access *call)
{
expression->prepare(program, file) ;
expression->type->generate_type_name(file, type_generate_class_reference) ;
fprintf(file, "local_%d = ", index) ;
expression->generate(program, file, type_generate_class_reference) ;
fprintf(file, " ;\n") ;
T_expression *loc = call->expressions.first ;
while (loc != NULL)
	{
	loc->prepare(program, file) ;
	loc = loc->next ;
	}
}

void T_expression_identifier_access::generate_call(T_entity_program *program, FILE *file, const T_expression_call_access *call)
{
if (method->object_class == NULL)
	{
	fprintf(file, "local_%d->%s(", index, method->name.string()) ;
	T_expression *loc = call->expressions.first ;
	loc->generate(program, file, type_generate_class_reference) ;
	loc = loc->next ;
	if (loc != NULL)
		{
		fprintf(file, ", ") ;
		loc->generate(program, file, type_generate_class_reference) ;
		}
	fprintf(file, ")") ;
	return ;
	}
else if (method->overloaded)
	{
	fprintf(file, "((") ;
	expression->type->generate_type_name(file, type_generate_header_reference) ;
	fprintf(file, ")local_%d)[-1].introspect->virtual_%s__%s(", index, method->object_class->name.string(), method->name.string()) ;
	}
else
	{
	if (introspect)
		{
		fprintf(file, "(") ;
		expression->type->generate_type_name(file, type_generate_class_reference) ;
		fprintf(file, ")") ;
		}
	fprintf(file, " _%s__%s(", method->object_class->name.string(), method->name.string()) ;
	}
int first = TRUE ;
T_prototype_argument *argument = method->type->prototype.arguments.first ;
T_expression *loc = call->expressions.first ;
while (argument != NULL)
	{
	if (first) first = FALSE ;
	else fprintf(file, ", ") ;
	if (strcmp(argument->name.string(), "self") == 0)
		{
		fprintf(file, "(") ;
		argument->type->generate_type_name(file, type_generate_class_reference) ;
		fprintf(file, ")local_%d", index) ;
		}
	else if (loc != NULL)
		{
		loc->generate(program, file, argument->is_reference ? type_generate_class_reference : type_generate_value) ;
		loc = loc->next ;
		}
	else
		{
		fprintf(file, "empty_vector") ;
		}
	argument = argument->next ;
	}
fprintf(file, ")") ;
}

// }{--------------------------------------------------------------

void T_expression_call_base::dump(FILE *file) const
{
fprintf(file, "... {") ;
T_expression *expression = expressions.first ;
if (expression != NULL)
	{
	for(;;)
		{
		expression->dump(file) ;
		expression = expression->next ;
		if (expression == NULL) break ;
		fprintf(file, ", ") ;
		}
	}
fprintf(file, "}") ;
}

void T_expression_call_base::parse(T_entity_compiler *compiler)
{
if (compiler->current_item == entity_compiler_item_left_parenthesis)
	{
	compiler->next_item() ;
	if (compiler->current_item == entity_compiler_item_right_parenthesis)
		{
		compiler->next_item() ;
		}
	else
		{
		for(;;)
			{
			T_expression *loc = compiler->parse_logical_or_expression() ;
			if (loc == NULL)
				{
				compiler->add_error(compiler->location, "expression expected.") ;
				return ;
				}
			expressions.insert(loc) ;
			if (compiler->current_item == entity_compiler_item_right_parenthesis)
				{
				compiler->next_item() ;
				return ;
				}
			if (compiler->current_item != entity_compiler_item_comma)
				{
				compiler->add_error(compiler->location, "comma or right parenthesis expected.") ;
				return ;
				}
			compiler->next_item() ;
			}
		}
	}
}

int T_expression_call_base::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
T_scope *scope_loc = scope ;
for(;;)
	{
	if (scope_loc == NULL)
		{
		compiler->add_error(location, "No base class.") ;
		return FALSE ;
		}
	if (scope_loc->is_constructor())
		{
		T_type *tmp = ((T_object_class_constructor_scope *)scope_loc)->constructor->object_class->base_type ;
		if (tmp->get_class() != class_type_identifier)
			{
			compiler->add_error(location, "bad base class for construct.") ;
			return FALSE ;
			}
		object_class = ((T_type_identifier *)tmp)->object_class ;
		if (object_class == NULL)
			{
			compiler->add_error(location, "class not found.") ;
			return FALSE ;
			}
		int ok = TRUE ;
		T_expression *loc = expressions.first ;
		while (loc != NULL)
			{
			if (!loc->verify_semantic(compiler, program, scope, method_type)) ok = FALSE ;
			loc = loc->next ;
			}
		if (!ok) return FALSE ;
		constructor = object_class->search_constructor(program, this) ;
		if (constructor == NULL)
			{
			compiler->add_error(location, "constructor not found.") ;
			return FALSE ;
			}
		type = new T_type_void(location) ;
		return TRUE ;
		}
	if (scope_loc->is_method())
		{
		T_type *tmp = ((T_object_class_method_scope *)scope_loc)->method->object_class->base_type ;
		if (tmp->get_class() != class_type_identifier)
			{
			compiler->add_error(location, "bad base class for construct.") ;
			return FALSE ;
			}
		object_class = ((T_type_identifier *)tmp)->object_class ;
		if (object_class == NULL)
			{
			compiler->add_error(location, "class not found.") ;
			return FALSE ;
			}
		int ok = TRUE ;
		T_expression *loc = expressions.first ;
		while (loc != NULL)
			{
			if (!loc->verify_semantic(compiler, program, scope, method_type)) ok = FALSE ;
			loc = loc->next ;
			}
		if (!ok) return FALSE ;
//		method = object_class->search_call(program, ((T_object_class_method_scope *)scope_loc)->method->name, this) ;
		method = object_class->search_base_method(((T_object_class_method_scope *)scope_loc)->method->base_method) ;
		if (method == NULL)
			{
			compiler->add_error(location, "method not found.") ;
			return FALSE ;
			}
		type = method->type->returned_type ;
		return TRUE ;
		}
	scope_loc = scope_loc->previous_scope ;
	}
}

void T_expression_call_base::prepare(T_entity_program *program, FILE *file)
{
T_expression *loc = expressions.first ;
while (loc != NULL)
	{
	loc->prepare(program, file) ;
	loc = loc->next ;
	}
}

void T_expression_call_base::generate(T_entity_program *program, FILE *file, int generate_type)
{
T_prototype_argument *argument = NULL ;
if (method != NULL)
	{
	fprintf(file, " _%s__%s(arg_self", method->object_class->name.string(), method->name.string()) ;
	argument = method->type->prototype.arguments.first ;
	argument = argument->next ;
	}
T_expression *loc = expressions.first ;
while (argument != NULL)
	{
	fprintf(file, ", ") ;
	if (loc != NULL)
		{
		loc->generate(program, file, argument->is_reference ? type_generate_class_reference : type_generate_value) ;
		loc = loc->next ;
		}
	else
		{
		fprintf(file, "empty_vector") ;
		}
	argument = argument->next ;
	}
fprintf(file, ")") ;
}

void T_expression_call_base::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
int label = jump_if_true ? true_label : false_label ;
if (jump_if_true) fprintf(file, "if (test(") ;
else fprintf(file, "if (!test(") ;
T_prototype_argument *argument = NULL ;
if (constructor != NULL)
	{
	fprintf(file, "constructor_%p(arg_self", constructor) ;
	argument = constructor->prototype.arguments.first ;
	if (argument != NULL) argument = argument->next ;
	}
if (method != NULL)
	{
	fprintf(file, " _%s__%s(arg_self", method->object_class->name.string(), method->name.string()) ;
	argument = method->type->prototype.arguments.first ;
	argument = argument->next ;
	}
T_expression *loc = expressions.first ;
while (argument != NULL)
	{
	fprintf(file, ", ") ;
	if (loc != NULL)
		{
		loc->generate(program, file, argument->is_reference ? type_generate_class_reference : type_generate_value) ;
		loc = loc->next ;
		}
	else
		{
		fprintf(file, "empty_vector") ;
		}
	argument = argument->next ;
	}
fprintf(file, ")") ;
fprintf(file, "))") ;
if (label == 0) fprintf(file, " break ;\n") ;
else fprintf(file, " goto label_%d ;\n", label) ;
}

void T_expression_call_base::generate_instruction(T_entity_program *program, FILE *file)
{
prepare(program, file) ;
T_prototype_argument *argument = NULL ;
if (constructor != NULL)
	{
	fprintf(file, "constructor_%p(arg_self", constructor) ;
	argument = constructor->prototype.arguments.first ;
	if (argument != NULL) argument = argument->next ;
	}
if (method != NULL)
	{
	fprintf(file, " _%s__%s(arg_self", method->object_class->name.string(), method->name.string()) ;
	argument = method->type->prototype.arguments.first ;
	argument = argument->next ;
	}
T_expression *loc = expressions.first ;
while (argument != NULL)
	{
	fprintf(file, ", ") ;
	if (loc != NULL)
		{
		loc->generate(program, file, argument->is_reference ? type_generate_class_reference : type_generate_value) ;
		loc = loc->next ;
		}
	else
		{
		fprintf(file, "empty_vector") ;
		}
	argument = argument->next ;
	}
fprintf(file, ") ;\n") ;
}

// }{--------------------------------------------------------------

void T_expression_call_access::dump(FILE *file) const
{
expression->dump(file) ;
fprintf(file, "(") ;
T_expression *expression = expressions.first ;
if (expression != NULL)
	{
	for(;;)
		{
		expression->dump(file) ;
		expression = expression->next ;
		if (expression == NULL) break ;
		fprintf(file, ", ") ;
		}
	}
fprintf(file, ")") ;
}

int T_expression_call_access::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
int ok = TRUE ;
T_expression *loc = expressions.first ;
while (loc != NULL)
	{
	if (!loc->verify_semantic(compiler, program, scope, method_type)) ok = FALSE ;
	loc = loc->next ;
	}
if (!ok) return FALSE ;
if (!expression->verify_call_semantic(compiler, program, scope, method_type, this)) return FALSE ;
type = expression->type ;
test = expression->test ;
return TRUE ;
}

void T_expression_call_access::prepare(T_entity_program *program, FILE *file)
{
if (constructor != NULL)
	{
	T_expression *loc = expressions.first ;
	while (loc != NULL)
		{
		loc->prepare(program, file) ;
		loc = loc->next ;
		}
	index = program->get_next_index() ;
	expression->get_type_expression()->generate_type_name(file, type_generate_value) ;
	fprintf(file, " local_%d ;\n", index) ;
	fprintf(file, "constructor_%p(&local_%d", constructor, index) ;
	T_prototype_argument *argument = constructor->prototype.arguments.first ;
	loc = expressions.first ;
	while (argument != NULL)
		{
		if (strcmp(argument->name.string(), "self") == 0)
			{
//			fprintf(file, "(") ;
//			argument->type->generate_type_name(file, type_generate_class_reference) ;
//			fprintf(file, ")local_%d", index) ;
			}
		else if (loc != NULL)
			{
			fprintf(file, ", ") ;
			loc->generate(program, file, argument->is_reference ? type_generate_class_reference : type_generate_value) ;
			loc = loc->next ;
			}
		else
			{
			fprintf(file, ", ") ;
			fprintf(file, "empty_vector") ;
			}
		argument = argument->next ;
		}
	fprintf(file, ") ;\n") ;
	}
else
	{
	expression->prepare_call(program, file, this) ;
	}
}

void T_expression_call_access::generate(T_entity_program *program, FILE *file, int generate_type)
{
if (constructor != NULL)
	{
	if (generate_type == type_generate_value) fprintf(file, "local_%d", index) ;
	else fprintf(file, "&local_%d", index) ;
	}
else
	{
	expression->generate_call(program, file, this) ;
	}
}

void T_expression_call_access::generate_test(T_entity_program *program, FILE *file, int jump_if_true, int true_label, int false_label)
{
int label = jump_if_true ? true_label : false_label ;
expression->prepare_call(program, file, this) ;
if (jump_if_true) fprintf(file, "if (test(") ;
else fprintf(file, "if (!test(") ;
expression->generate_call(program, file, this) ;
fprintf(file, "))") ;
if (label == 0) fprintf(file, " break ;\n") ;
else fprintf(file, " goto label_%d ;\n", label) ;
}

void T_expression_call_access::generate_instruction(T_entity_program *program, FILE *file)
{
fprintf(file, "/* prepare_call*/\n") ;
expression->prepare_call(program, file, this) ;
fprintf(file, "/* generate_call*/\n") ;
expression->generate_call(program, file, this) ;
fprintf(file, " ;\n") ;
fprintf(file, "/*end*/\n") ;
}

void T_expression_call_access::generate_constructor(T_entity_program *program, FILE *file, const T_string name)
{
expression->prepare_call(program, file, this) ;
expression->generate_constructor(program, file, name, this) ;
}

// }{--------------------------------------------------------------

void T_expression_array_access::dump(FILE *file) const
{
expression->dump(file) ;
fprintf(file, "[") ;
T_expression *expression = expressions.first ;
if (expression != NULL)
	{
	for(;;)
		{
		expression->dump(file) ;
		expression = expression->next ;
		if (expression == NULL) break ;
		fprintf(file, ", ") ;
		}
	}
fprintf(file, "]") ;
}

int T_expression_array_access::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
compiler->add_error(location, "array not implemented.") ;
return TRUE ;
}

// }{--------------------------------------------------------------

void T_expression_post_increment::dump(FILE *file) const
{
expression->dump(file) ;
fprintf(file, " ++") ;
}

int T_expression_post_increment::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
if (expression->test) compiler->add_error(expression->location, "test not expected here.") ;
if (!program->is_increment(expression->type))
	{
	compiler->add_error(expression->location, "bad type for post increment.") ;
	return FALSE ;
	}
type = new T_type_void(location) ;
return TRUE ;
}

void T_expression_post_increment::generate(T_entity_program *program, FILE *file, int generate_type)
{
expression->generate(program, file, type_generate_value) ;
fprintf(file, "++") ;
}

void T_expression_post_increment::generate_instruction(T_entity_program *program, FILE *file)
{
program->generate_post_increment(file, expression) ;
fprintf(file, " ;\n") ;
}

// }{--------------------------------------------------------------

void T_expression_post_decrement::dump(FILE *file) const
{
expression->dump(file) ;
fprintf(file, " --") ;
}

int T_expression_post_decrement::verify_semantic(T_entity_compiler *compiler, T_entity_program *program, T_scope *scope, T_type_method *method_type)
{
if (!expression->verify_semantic(compiler, program, scope, method_type)) return FALSE ;
if (expression->test) compiler->add_error(expression->location, "test not expected here.") ;
if (!program->is_increment(expression->type))
	{
	compiler->add_error(expression->location, "bad type for post decrement.") ;
	return FALSE ;
	}
type = new T_type_void(location) ;
return TRUE ;
}

void T_expression_post_decrement::generate(T_entity_program *program, FILE *file, int generate_type)
{
expression->generate(program, file, type_generate_value) ;
fprintf(file, "--") ;
}

void T_expression_post_decrement::generate_instruction(T_entity_program *program, FILE *file)
{
program->generate_post_decrement(file, expression) ;
fprintf(file, " ;\n") ;
}

// }{--------------------------------------------------------------
